﻿using System.Collections.Concurrent;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Reflection;

using Microsoft.Extensions.Logging;

using zijian666.Core;
using zijian666.Core.Abstractions;
using zijian666.DI.Abstractions;

namespace zijian666.DI;

/// <summary>
/// 成员装配描述类
/// </summary>
public record class AutowiredDescriptor
{
    /// <summary>
    /// 缓存
    /// </summary>
    private static readonly ConcurrentDictionary<Type, ImmutableArray<AutowiredDescriptor>?> _cache = new();

    /// <summary>
    /// 获取指定类型的装配描述
    /// </summary>
    public static IEnumerable<AutowiredDescriptor> FormType(Type? serviceType)
        => serviceType is null ? [] : _cache.GetOrAdd(serviceType, Build) as IEnumerable<AutowiredDescriptor> ?? [];

    /// <summary>
    /// 获取指定属性的装配描述
    /// </summary>
    public static AutowiredDescriptor? FormProperty(PropertyInfo property)
        => FormType(property.ReflectedType).FirstOrDefault(x => x.Member == property);

    /// <summary>
    /// 获取指定字段的装配描述
    /// </summary>
    public static AutowiredDescriptor? FormField(FieldInfo field)
        => FormType(field.ReflectedType).FirstOrDefault(x => x.Member == field);

    public static bool HasAutowired(Type serviceType)
        => FormType(serviceType).Any();

    private static ImmutableArray<AutowiredDescriptor>? Build(Type serviceType)
    {
        var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

        var descriptors = new List<AutowiredDescriptor>();

        var type = serviceType;
        while (type != typeof(object) && type != null)
        {


            descriptors.AddRange(type.GetFields(flags)
                                .Where(x => type == serviceType || x.IsPrivate)
                                .Where(x => x.IsDefined(typeof(AutowiredAttribute)))
                                .Select(x => new AutowiredDescriptor(x, x.GetCustomAttribute<AutowiredAttribute>()!)));
            descriptors.AddRange(type.GetProperties(flags)
                                .Where(x => type == serviceType || x.GetSetMethod()?.IsPrivate == true)
                                .Where(x => x.IsDefined(typeof(AutowiredAttribute)) && x.GetSetMethod(true) is not null)
                                .Select(x => new AutowiredDescriptor(x, x.GetCustomAttribute<AutowiredAttribute>()!)));
            type = type.BaseType;

        }

        if (descriptors.Count == 0)
        {
            return null;
        }

        return descriptors.ToImmutableArray();
    }


    private readonly MemberSetter<object> _setValue;

    /// <summary>
    /// 构造函数
    /// </summary>
    public AutowiredDescriptor(FieldInfo field, AutowiredAttribute attribute)
    {
        ArgumentNullException.ThrowIfNull(field);
        if (field.IsLiteral)
        {
            throw new NotSupportedException($"{field.ReflectedType?.FullName}.{field.Name} 装配服务失败: 字段是常量");
        }
        var reflect = FeatureManager.Get<IReflectCompiler>();
        _setValue = field.IsInitOnly
            ? field.SetValue
            : reflect.CompileSetter<object>(field);
        //_setValue = field.SetValue;
        ClassName = field.ReflectedType?.FullName ?? "";
        MemberName = field.Name;
        FieldType = field.FieldType;
        Member = field;
        Attribute = attribute;
        ServiceType = GetServiceType(attribute.ServiceType);
        ValidationAttributes = Member.GetCustomAttributes<ValidationAttribute>().ToImmutableArray();
        DisplayName = Member.GetCustomAttribute<DisplayAttribute>()?.Name ?? MemberName;
        RequiredAttribute = Member.GetCustomAttribute<RequiredAttribute>();
        if (attribute.AutowiredHandler is not null)
        {
            Handler = (IAutowiredHandler?)Activator.CreateInstance(attribute.AutowiredHandler);
        }
    }

    /// <summary>
    /// 构造函数
    /// </summary>
    public AutowiredDescriptor(PropertyInfo prop, AutowiredAttribute attribute)
    {
        ArgumentNullException.ThrowIfNull(prop);
        var setter = prop.GetSetMethod(true)
            ?? throw new NotSupportedException($"{prop.ReflectedType?.FullName}.{prop.Name} 装配服务失败: 属性没有 set 方法");
        var reflect = FeatureManager.Get<IReflectCompiler>();
        _setValue = setter.IsPrivate
            ? (obj, arg) => setter.Invoke(obj, [arg])
            : reflect.CompileSetter<object>(prop);

        ClassName = prop.ReflectedType?.FullName ?? "";
        MemberName = prop.Name;
        FieldType = prop.PropertyType;
        Member = prop;
        Attribute = attribute;
        ServiceType = GetServiceType(attribute.ServiceType);
        ValidationAttributes = Member.GetCustomAttributes<ValidationAttribute>().ToImmutableArray();
        DisplayName = Member.GetCustomAttribute<DisplayAttribute>()?.Name ?? MemberName;
        RequiredAttribute = Member.GetCustomAttribute<RequiredAttribute>();
        if (attribute.AutowiredHandler is not null)
        {
            Handler = (IAutowiredHandler?)Activator.CreateInstance(attribute.AutowiredHandler);
        }
    }

    /// <summary>
    /// 自动装配处理器
    /// </summary>
    public IAutowiredHandler? Handler { get; }

    /// <summary>
    /// 必填特性
    /// </summary>
    public RequiredAttribute? RequiredAttribute { get; }

    /// <summary>
    /// 验证特性
    /// </summary>
    public ImmutableArray<ValidationAttribute> ValidationAttributes { get; }

    /// <summary>
    /// 显示名称
    /// </summary>
    public string DisplayName { get; }
    /// <summary>
    /// 成员名称
    /// </summary>
    public string MemberName { get; }

    /// <summary>
    /// 类名
    /// </summary>
    public string ClassName { get; }

    /// <summary>
    /// 成员类型
    /// </summary>
    public Type FieldType { get; }

    /// <summary>
    /// 服务类型
    /// </summary>
    public Type ServiceType { get; }

    /// <summary>
    /// 成员信息
    /// </summary>
    public MemberInfo Member { get; }

    /// <summary>
    /// 特性
    /// </summary>
    public AutowiredAttribute Attribute { get; }

    /// <summary>
    /// 是否为键值服务
    /// </summary>
    public bool IsKeyedService => Attribute.Key is not null;

    /// <summary>
    /// 处理一些特殊类型
    /// </summary>
    private Type GetServiceType(Type? serviceType)
    {
        var type = serviceType ?? FieldType;

        if (type == typeof(ILogger) && Member.ReflectedType is not null)
        {
            type = typeof(ILogger<>).MakeGenericType(Member.ReflectedType);
        }
        if (type == typeof(IServiceProvider))
        {
            throw new NotSupportedException($"{ClassName}.{MemberName} 装配服务失败: 不能直接装配 IServiceProvider 服务，请改用 SingletonServiceProvider、ScopedServiceProvider 或 TransientServiceProvider");
        }
        return type;
    }

    public void SetValue(IAutowiredContext context, object instance, object value)
    {
        ArgumentNullException.ThrowIfNull(instance);
        ArgumentNullException.ThrowIfNull(value);
        value = Handler?.Rewrite(context, this, instance, value) ?? value;
        if (Attribute.Validate)
        {
            var validationContext = new ValidationContext(value);
            Validator.ValidateObject(value, validationContext, true);
        }

        if (ValidationAttributes.Length > 0)
        {
            var validationContext = new ValidationContext(instance) { MemberName = MemberName, DisplayName = DisplayName };
            Validator.ValidateValue(value, validationContext, ValidationAttributes);
        }
        _setValue(instance, value);
    }
}